package com.baoai.service;

import com.baoai.common.BeanFactory;
import com.baoai.common.IConstant;
import com.baoai.controller.IndexController;
import com.baoai.dao.IndexDao;
import com.baoai.dto.BaseDto;
import com.baoai.util.BaseUtil;
import org.apache.log4j.Logger;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.*;

/**
 * Created by xiaren on 2017/4/6.
 */
@Service
public class IndexService {

    private static final Logger LOGGER = Logger.getLogger(IndexController.class);

    @Autowired
    private IndexDao indexDao;

    /**
     * 新增或修改
     * @param baseDto
     * @return
     * @throws IOException
     */
    public Object saveOrUpdate(BaseDto baseDto) throws IOException {
        Object object = null;
        if (baseDto.getCreateDate() == null) {
            baseDto.setCreateDate(System.currentTimeMillis());
        }
        if (baseDto.getUpdateDate() == null) {
            baseDto.setUpdateDate(baseDto.getCreateDate());
        }
        String id = BaseUtil.getIdValueByName(baseDto);
        BaseDto targetDto = (BaseDto) findIndexById(id, (Class<BaseDto>) baseDto.getClass());
        if (targetDto == null) {
            baseDto.setId(UUID.randomUUID().toString());
            object = indexDao.save(baseDto);
        } else {
            BaseUtil.copySource2Target(baseDto, targetDto);
            object = indexDao.update(targetDto);
        }
        return object;
    }

    /**
     * 公共查询
     * @param searchText
     * @param className
     * @param sex
     * @param channel
     * @param pageIndex
     * @param pageSize
     * @return
     * @throws IOException
     */
    public List<Object> queryCommonList(String searchText, String className, String sex, String channel, int pageIndex, int pageSize, String stateArray) throws IOException {
        List<Object> objectList = null;
        String[] searchArray = BaseUtil.ikSeqWord(searchText);

        Sort sort = new Sort(new SortField[]
                {
                        // 按照相关度查询，然后再按照权重排序
                        new SortField("learnNumber", SortField.Type.INT, true),
                        new SortField("visitorNumber", SortField.Type.INT, true),
                        new SortField("learnNumber", SortField.Type.INT, true),
                        new SortField("start", SortField.Type.INT, true),
                        new SortField("commentNumber", SortField.Type.INT, true)
                }
        );
        Query query = null;
        if (searchArray == null || searchArray.length == 0) { // 当是空查询的时候
            query = new MatchAllDocsQuery();
        } else {
            List<Query> collectQuery = createQuery(searchArray);
            query = new DisjunctionMaxQuery(collectQuery, 0.1F);
        }
        query = createCommentQuery(query, className, sex, channel, null, stateArray);
        objectList = indexDao.commQuery(query, sort, pageIndex, pageSize);
        return objectList;
    }

    /**
     * 查询我推荐的内容
     * @param recommend
     * @param channelId
     * @param pageIndex
     * @param pageSize
     * @return
     * @throws IOException
     */
    public List<Object> queryRecommend(String recommend, String channelId, int pageIndex, int pageSize) throws IOException {
        List<Object> objectList = null;
        BooleanQuery.Builder booleanQuery = new BooleanQuery.Builder();
        Query queryRecommend = new MatchAllDocsQuery();
        if (!StringUtils.isEmpty(recommend)) {
            queryRecommend = new TermQuery(new Term("recommend", recommend));
        }
        booleanQuery.add(queryRecommend, BooleanClause.Occur.MUST);
        if (!StringUtils.isEmpty(channelId)) {
            Query channelQuery = new TermQuery(new Term("channelId", channelId));
            booleanQuery.add(channelQuery, BooleanClause.Occur.MUST);
        }
        // 查询启用的
        Query queryState = new TermQuery(new Term("state", "1"));
        booleanQuery.add(queryState, BooleanClause.Occur.MUST);

        objectList = indexDao.commQuery(booleanQuery.build(), null, pageIndex, pageSize);
        return objectList;
    }


    /**
     * 导师查询
     * @param searchText
     * @param orderType
     * @param goodAt
     * @param pageIndex
     * @param pageSize
     * @return
     * @throws IOException
     */
    public List<Object> queryTutorList(String searchText, String orderType, String goodAt, int pageIndex, int pageSize, String stateArray) throws IOException {
        List<Object> objectList = null;
        String[] searchArray = BaseUtil.ikSeqWord(searchText);
        Sort sort = new Sort(new SortField[]
                {
                        new SortField("praisePercen", SortField.Type.INT, true),//注释掉这个就是按照相关度排序
                        // 按照相关度查询，然后再按照权重排序
                        new SortField("learnNumber", SortField.Type.INT, true)//注释掉这个就是按照相关度排序
                }
        );
        if ("1".equals(orderType)) {   // 好评
            sort = new Sort(new SortField[]
                    {
                            new SortField("praisePercen", SortField.Type.INT, true)//注释掉这个就是按照相关度排序
                    }
            );
        } else if ("2".equals(orderType)) {   // 咨询
            sort = new Sort(new SortField[]
                    {
                            new SortField("learnNumber", SortField.Type.INT, true),//注释掉这个就是按照相关度排序
                    }
            );
        }
        Query query = null;
        if (searchArray == null || searchArray.length == 0) { // 当是空查询的时候
            query = new MatchAllDocsQuery();
        } else {
            List<Query> collectQuery = createQuery(searchArray);
            query = new DisjunctionMaxQuery(collectQuery, 0.1F);
        }
        query = createCommentQuery(query, "tutor", null, null, goodAt, stateArray);

        objectList = indexDao.commQuery(query, sort, pageIndex, pageSize);
        return objectList;
    }

    /**
     * 我资源的评论集合
     * @param tutorId
     * @param pageIndex
     * @param pageSize
     * @return
     * @throws IOException
     */
    public List<Object> querySourceComment(Integer tutorId, Integer pageIndex, Integer pageSize) throws IOException {
        List<Query> tutorQueryList = new ArrayList<>();
        for (int i = 0; i < IConstant.TUTOR_NUMBER; i++) {
            tutorQueryList.add(new MultiPhraseQuery.Builder().add(new Term("tutorIdJson" + i, String.valueOf(tutorId))).build());
        }
        Query queryTutor = new DisjunctionMaxQuery(tutorQueryList, 0);
        Sort sort = new Sort(new SortField("createDate", SortField.Type.LONG, true));

        Query queryBase = new TermQuery(new Term("isBase", "1"));

        Query queryComment = new TermQuery(new Term("className", "comment"));
        BooleanQuery.Builder booleanQuery = new BooleanQuery.Builder();
        booleanQuery.add(queryTutor, BooleanClause.Occur.MUST);
        booleanQuery.add(queryBase, BooleanClause.Occur.MUST);
        booleanQuery.add(queryComment, BooleanClause.Occur.MUST);

        List<Object> objectList = indexDao.commQuery(booleanQuery.build(), sort, pageIndex, pageSize);
        return objectList;
    }

    /**
     * 查询我的资源下面我的回复
     * @param memberId
     * @param baseIds
     * @return
     * @throws IOException
     */
    public Map<String, Object> queryMyComment(String memberId, List<String> baseIds) throws IOException {
        Map<String, Object> resultMap = new HashMap();
        for (String baseId : baseIds) {
            Query queryBaseId = new TermQuery(new Term("baseId", baseId));
            Query queryMemberId = new TermQuery(new Term("memberId", memberId));
            BooleanQuery.Builder booleanQuery = new BooleanQuery.Builder();
            booleanQuery.add(queryMemberId, BooleanClause.Occur.MUST);
            booleanQuery.add(queryBaseId, BooleanClause.Occur.MUST);
            Object obj = indexDao.getSignIndex(booleanQuery.build(), null);
            resultMap.put(baseId, obj);
        }
        return resultMap;
    }

    public List<Object> queryMyPublish(String searchText, Integer tutorId, String stateArray, String className, Integer pageIndex, Integer pageSize) throws IOException {
        String[] searchArray = BaseUtil.ikSeqWord(searchText);
        Query query = null;
        if (searchArray == null || searchArray.length == 0) { // 当是空查询的时候
            query = new MatchAllDocsQuery();
        } else {
            List<Query> queryList = createQuery(searchArray);
            query = new DisjunctionMaxQuery(queryList, 0.1F);
        }

        List<Query> tutorList = new ArrayList<>();
        for (int i = 0; i < IConstant.TUTOR_NUMBER; i++) {
            tutorList.add(new MultiPhraseQuery.Builder().add(new Term("tutorIdJson" + i, String.valueOf(tutorId))).build());
        }
        tutorList.add(new MultiPhraseQuery.Builder().add(new Term("tutorId", String.valueOf(tutorId))).build());
        Query queryTutorId = new DisjunctionMaxQuery(tutorList, 0.1F);
        BooleanQuery.Builder booleanQuery = new BooleanQuery.Builder();
        booleanQuery.add(query, BooleanClause.Occur.MUST);
        booleanQuery.add(queryTutorId, BooleanClause.Occur.MUST);
        query = buildState(query, stateArray);

        if(StringUtils.isEmpty(className)){
            Term[] terms = {
                    new Term("className", "article"),
                    new Term("className", "course"),
                    new Term("className", "video"),
            };
            Query queryClassName = new MultiPhraseQuery.Builder().add(terms).build();
            booleanQuery.add(queryClassName, BooleanClause.Occur.MUST);
        } else {
            Query queryClassName = new TermQuery(new Term("className", className));
            booleanQuery.add(queryClassName, BooleanClause.Occur.MUST);
        }
        query = buildState(query, stateArray);
        query = booleanQuery.build();

        List<Object> objectList = indexDao.commQuery(query, new Sort(), pageIndex, pageSize);
        return objectList;
    }

    /**
     * 根据id查询
     * @param id
     * @param cls
     * @return
     * @throws IOException
     */
    public Object findIndexById(String id, Class cls) throws IOException {
        Object obj = null;
        Repository repository = (Repository) cls.getAnnotation(Repository.class);
        Query query1 = new TermQuery(new Term(BaseUtil.getIdName(cls), id));
        Query query2 = new TermQuery(new Term(IConstant.CLASSNAME, repository.value()));

        BooleanQuery.Builder booleanQuery = new BooleanQuery.Builder();
        booleanQuery.add(query1, BooleanClause.Occur.MUST);
        booleanQuery.add(query2, BooleanClause.Occur.MUST);
        obj = indexDao.findIndexById(booleanQuery.build());
        return obj;
    }

    /**
     * 查询所有
     * @return
     * @throws ClassNotFoundException
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws IOException
     */
    public List<Object> queryList() throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException {
        List<Object> videoDtoList = null;
        videoDtoList = indexDao.queryAllList();
        return videoDtoList;
    }

    /**
     * 删除所有
     * @throws IOException
     */
    public void deleteAllIndex() throws IOException {
        indexDao.deleteAllIndex();
    }

    /**
     * 根据id、类别查询
     * @param id
     * @param className
     * @throws IOException
     */
    public void deleteById(String id, String className) throws IOException {
        BaseDto baseDto = (BaseDto) BeanFactory.getBean(className);
        if (baseDto == null) {
            throw new RuntimeException("找不到该className=" + className);
        }
        BaseDto targetDto = (BaseDto) findIndexById(id, (Class<BaseDto>) baseDto.getClass());
        if (targetDto == null) {
            throw new RuntimeException("找不到ID=" + id + ",className=" + className);
        }
        indexDao.deleteById(targetDto.getId(), baseDto.getClass());
    }


    /**
     * 根据数组查询
     *
     * @param searchArray
     * @return
     */
    private List<Query> createQuery(String[] searchArray) {
        List<Query> collectQuery = new ArrayList<>();
        String[] array = IConstant.QUERY_NAME;
        for (String queryName : array) {
            collectQuery.add(new MultiPhraseQuery.Builder().add(buildTerms(queryName, searchArray)).build());
        }
        return collectQuery;
    }

    /**
     * 创建查询单元
     *
     * @param fieldName
     * @param searchArray
     * @return
     */
    private Term[] buildTerms(String fieldName, String[] searchArray) {
        Term[] terms = new Term[searchArray.length];
        for (int i = 0; i < searchArray.length; i++) {
            terms[i] = new Term(fieldName, searchArray[i]);
        }
        return terms;
    }

    /**
     * 创建公共查询条件
     *
     * @param query
     * @param className
     * @param sex
     * @param channel
     * @param goodAt
     * @return
     * @throws IOException
     */
    private Query createCommentQuery(Query query, String className, String sex, String channel, String goodAt, String stateArray) throws IOException {
        if (!StringUtils.isEmpty(className)) {    // 查询类别
            Query queryType = new TermQuery(new Term(IConstant.CLASSNAME, className));
            BooleanQuery.Builder booleanQuery = new BooleanQuery.Builder();
            booleanQuery.add(query, BooleanClause.Occur.MUST);
            booleanQuery.add(queryType, BooleanClause.Occur.MUST);
            query = booleanQuery.build();
        }
        if (!StringUtils.isEmpty(sex)) {   // 查询男女
            Query querySex = new TermQuery(new Term(IConstant.SEX, sex));
            BooleanQuery.Builder booleanQuery = new BooleanQuery.Builder();
            booleanQuery.add(query, BooleanClause.Occur.MUST);
            booleanQuery.add(querySex, BooleanClause.Occur.MUST);
            query = booleanQuery.build();
        }
        if (!StringUtils.isEmpty(channel)) {   // 查询频道
            Query queryChannel = new TermQuery(new Term(IConstant.CHANNELID, channel));
            BooleanQuery.Builder booleanQuery = new BooleanQuery.Builder();
            booleanQuery.add(query, BooleanClause.Occur.MUST);
            booleanQuery.add(queryChannel, BooleanClause.Occur.MUST);
            query = booleanQuery.build();
        }
        if (!StringUtils.isEmpty(goodAt)) {    // 擅长领域
            List<Query> collectQuery = new ArrayList<>();
            for (int i = 0; i < IConstant.GOODAT_NUMBER; i++) {
                collectQuery.add(new MultiPhraseQuery.Builder().add(new Term("goodAtIdJson" + i, goodAt)).build());
            }
            Query queryGoodAt = new DisjunctionMaxQuery(collectQuery, 0.1F);
            BooleanQuery.Builder booleanQuery = new BooleanQuery.Builder();
            booleanQuery.add(query, BooleanClause.Occur.MUST);
            booleanQuery.add(queryGoodAt, BooleanClause.Occur.MUST);
            query = booleanQuery.build();
        }
        query = buildState(query, stateArray);
        return query;
    }

    private Query buildState(Query query, String stateArray){
        if(!StringUtils.isEmpty(stateArray)){
            BooleanQuery.Builder booleanQuery = new BooleanQuery.Builder();
            String[] arrayState = stateArray.split(",");
            Term[] terms = new Term[arrayState.length];
            for (int index = 0; index < arrayState.length; index++){
                terms[index] = new Term("state", arrayState[index]);
            }
            Query queryState = new MultiPhraseQuery.Builder().add(terms).build();
            booleanQuery.add(queryState, BooleanClause.Occur.MUST);
            booleanQuery.add(query, BooleanClause.Occur.MUST);
            query = booleanQuery.build();
        }
        return query;
    }

}
